package com.hobee.basic.utils;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import org.springframework.util.StringUtils;
import sun.misc.BASE64Encoder;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author junjie.li
 * @date 2020/7/16 17:45
 */
public final class QrCodeUtil {

    private static final int QR_COLOR = 0xFF000000;
    private static final int BG_WHITE = 0xFFFFFFFF;

    /**
     * 生成二维码Png图片的Base64
     *
     * @param content 二维码内容
     * @return 二维码Png图片的Base64
     */
    public static String generateQrCodeBase64(String content) {
        return generateQrCodeBase64(content, null, null);
    }

    /**
     * 生成二维码Png图片的Base64
     *
     * @param content  内容
     * @param logoPath logo路径
     * @return 二维码Png图片的Base64
     */
    public static String generateQrCodeBase64(String content, String logoPath, String word) {
        return generateQrCodeBase64(content, 200, 200, logoPath, word);
    }

    /**
     * 生成二维码Png图片的Base64
     *
     * @param content 二维码内容
     * @param width   宽
     * @param height  高
     * @return 二维码Png图片的Base64
     */
    public static String generateQrCodeBase64(String content, int width, int height, String logoPath, String word) {
        // 设置图片的文字编码以及内边框
        Map<EncodeHintType, Object> hints = new HashMap<>(2);
        // 编码
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        // 边框距
        hints.put(EncodeHintType.MARGIN, 0);

        return generateQrCodeBase64(content, width, height, hints, logoPath, word);
    }

    /**
     * 生成二维码Png图片的Base64
     *
     * @param content 二维码内容
     * @param width   宽
     * @param height  高
     * @param hints   自定义提供给编码器的其他参数
     * @return 二维码Png图片的Base64
     */
    public static String generateQrCodeBase64(String content, int width, int height, Map<EncodeHintType, Object> hints, String logoPath, String word) {
        final BitMatrix bitMatrix;
        String binary = null;
        try {
            bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            BufferedImage image = toBufferedImage(bitMatrix);
            if (!StringUtils.isEmpty(logoPath)) {
                withLogoMatrix(image, logoPath);
            }
            if (!StringUtils.isEmpty(word)) {
                image = withText(image, word);
            }
            ImageIO.write(image, "PNG", out);
            byte[] bytes = out.toByteArray();
            BASE64Encoder encoder = new BASE64Encoder();
            binary = encoder.encodeBuffer(bytes).trim();
        } catch (WriterException | IOException e) {
            e.printStackTrace();
        }
        return binary;
    }

    public static BufferedImage toBufferedImage(BitMatrix matrix) {
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, matrix.get(x, y) ? QR_COLOR : BG_WHITE);
            }
        }
        return image;
    }

    /**
     * 给二维码添加图片
     *
     * @param matrixImage {@link BufferedImage}
     * @param logoPath    logoPath
     * @return BufferedImage
     * @throws IOException ex
     */
    public static BufferedImage withLogoMatrix(BufferedImage matrixImage, String logoPath) throws IOException {
        // 在二维码上画logo:产生一个  二维码画板
        Graphics2D g2 = matrixImage.createGraphics();

        // 画logo： String->BufferedImage(内存)
        BufferedImage logoImg = ImageIO.read(new File(logoPath));
        int height = matrixImage.getHeight();
        int width = matrixImage.getWidth();
        // 纯logo图片
        g2.drawImage(logoImg, width * 2 / 5, height * 2 / 5, width / 5, height / 5, null);

        // 产生一个 画 白色圆角正方形的 画笔
        BasicStroke stroke = new BasicStroke(5, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        // 将画板-画笔 关联
        g2.setStroke(stroke);
        // 创建一个正方形
        //noinspection IntegerDivisionInFloatingPointContext
        RoundRectangle2D.Float round = new RoundRectangle2D.Float(width * 2 / 5, height * 2 / 5, width / 5, height / 5, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        g2.setColor(Color.WHITE);
        g2.draw(round);

        // 灰色边框
        BasicStroke stroke2 = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        g2.setStroke(stroke2);
        // 创建一个正方形
        //noinspection IntegerDivisionInFloatingPointContext
        RoundRectangle2D.Float round2 = new RoundRectangle2D.Float(width * 2 / 5 + 2, height * 2 / 5 + 2, width / 5 - 4, height / 5 - 4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        // Color color = new Color(128,128,128) ;
        g2.setColor(Color.GRAY);
        g2.draw(round2);
        g2.dispose();
        matrixImage.flush();

        return matrixImage;
    }

    /**
     * 添加文字
     *
     * @param pressText   文字
     * @param matrixImage BufferedImage
     */
    public static BufferedImage withText(BufferedImage matrixImage, String pressText) {
        // x开始的位置：（图片宽度-字体大小*字的个数）/2
        int wordSize = 20;
        int startx = (matrixImage.getWidth() - (wordSize * pressText.length())) / 2;
        // y开始的位置：图片高度-（图片高度-图片宽度）/2
        int starty = matrixImage.getHeight() - (matrixImage.getHeight() - matrixImage.getWidth()) / 2;

        BufferedImage wordImage = new BufferedImage(matrixImage.getWidth(), matrixImage.getHeight() + wordSize + 5, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = wordImage.createGraphics();

        g.drawImage(matrixImage, 0, 0, matrixImage.getWidth(), matrixImage.getHeight(), null);
        g.setColor(Color.red);
        g.setFont(new Font("粗体", Font.BOLD, wordSize));

        g.drawString(pressText, startx, starty + wordSize);
        g.dispose();
        wordImage.flush();
        return wordImage;

    }

    public static void main(String[] args) {
        String s = generateQrCodeBase64("http://www.niceloo.com/", "C:\\Users\\Administrator\\Desktop\\youlu-logo.png", "优路教育");
        System.out.println(s);
    }

}
